<?php

namespace App\Http\Requests;

use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Validator;
use Symfony\Component\HttpFoundation\Response;

class BaseRequest extends FormRequest
{
    public array $scenes = [];
    public string $currentScene;               //当前场景
    public bool $autoValidate = false;       //是否注入之后自动验证
    public array $extendRules;

    public function authorize()
    {
        return true;
    }

    /**
     * 设置场景
     * @param $scene
     * @return $this
     */
    public function scene($scene)
    {
        $this->currentScene = $scene;
        return $this;
    }


    /**
     *使用扩展rule
     * @param string $name
     * @return $this
     */
    public function with($name = '')
    {
        if (is_array($name)) {
            $this->extendRules = array_merge(
                $this->extendRules[],
                array_map(
                    function ($v) {
                        return Str::camel($v);
                    },
                    $name
                )
            );
        } else {
            if (is_string($name)) {
                $this->extendRules[] = Str::camel($name);
            }
        }

        return $this;
    }

    /**
     * 覆盖自动验证方法
     */
    public function validateResolved()
    {
        if ($this->autoValidate) {
            try {
                $this->handleValidate();
            } catch (AuthorizationException | ValidationException $e) {

            }
        }
    }

    /**
     * 验证方法
     * @param string $scene
     * @throws \Illuminate\Auth\Access\AuthorizationException
     * @throws \Illuminate\Validation\ValidationException
     */
    public function validate($scene = '')
    {
        if ($scene) {
            $this->currentScene = $scene;
        }
        $this->handleValidate();
    }

    /**
     * 根据场景获取规则
     * @return array|mixed
     */
    public function getRules()
    {
        $rules = $this->container->call([$this, 'rules']);
        $newRules = [];
        if (isset($this->extendRules) &&  $this->extendRules) {
            $extendRules = array_reverse($this->extendRules);
            foreach ($extendRules as $extendRule) {
                if (method_exists($this, "{$extendRule}Rules")) {   //合并场景规则
                    $rules = array_merge(
                        $rules,
                        $this->container->call([$this, "{$extendRule}Rules"])
                    );
                }
            }
        }
        if ($this->currentScene && isset($this->scenes[$this->currentScene])) {
            $sceneFields = is_array($this->scenes[$this->currentScene])
                ? $this->scenes[$this->currentScene] : explode(',', $this->scenes[$this->currentScene]);
            foreach ($sceneFields as $field) {
                if (array_key_exists($field, $rules)) {
                    $newRules[$field] = $rules[$field];
                }
            }
            return $newRules;
        }
        return $rules;
    }

    /**
     * 覆盖设置 自定义验证器
     * @param $factory
     * @return mixed
     */
    public function validator($factory)
    {
        return $factory->make(
            $this->validationData(), $this->getRules(),
            $this->messages(), $this->attributes()
        );
    }

    /**
     * 最终验证方法
     * @throws \Illuminate\Auth\Access\AuthorizationException
     * @throws \Illuminate\Validation\ValidationException
     */
    protected function handleValidate()
    {
        $instance = $this->getValidatorInstance();
        if ($instance->fails()) {

            $this->failedValidation($instance);
        }
        $this->passedValidation();
    }

    /**
     * @param Validator $validator
     * @desc
     * @return void
     * @throws ValidationException
     * @author: ckg
     * @Time: 2022/11/9 14:26
     */
    protected function failedValidation(Validator|\Illuminate\Contracts\Validation\Validator $validator): void
    {
        $error = $validator->errors()->all();
        throw new Exception($error[0], Response::HTTP_UNPROCESSABLE_ENTITY);
    }

}
